package com.example.ssyinitlearn.authenticationProvider;

import org.springframework.http.MediaType;
import org.springframework.security.authentication.AuthenticationServiceException;
import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;

/**
 * 覆写 DaoAuthenticationProvider 的认证方法，添加验证码校验工作
 * 显然这不是一个Bean
 */
public class MyDaoAuthenticationProvider extends DaoAuthenticationProvider {
    /**
     * 覆写其 authenticate 方法
     *
     * @param authentication
     * @return
     * @throws AuthenticationException
     */
    @Override
    public Authentication authenticate(Authentication authentication) throws AuthenticationException {
        // 以下内容为 当方法请求头不允许添加 HttpServletRequest参数时，如何获取?
        ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        assert requestAttributes != null;
        HttpServletRequest httpServletRequest = requestAttributes.getRequest();
        // 验证请求格式，如果是JSON则不进行验证码验证的环节
        if (!httpServletRequest.getContentType().equalsIgnoreCase(MediaType.APPLICATION_JSON_VALUE)
                && !httpServletRequest.getContentType().equalsIgnoreCase(MediaType.APPLICATION_JSON_UTF8_VALUE)) {
            // 获取到 HttpServletRequest之后就和平常一样进行处理即可
            String kaptcha = httpServletRequest.getParameter("kaptcha");  // login1.html 中设置验证码的标识为 kaptcha
            // 从session中将之前填入的验证码拿出来
            String kaptchaSession = (String) httpServletRequest.getSession().getAttribute("kaptcha");
            // 比较验证码
            if (kaptcha == null || !kaptcha.equals(kaptchaSession)) {
                throw new AuthenticationServiceException("验证码错误");
            }
        }
        // 验证通过，就接着执行父类原始的 authenticate方法，依然是使用 super
        return super.authenticate(authentication);
    }
}
